[HVM][VMX] Fix data copying in transition to/from vmxassist.
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Fri, 29 Sep 2006 09:30:18 +0000 (10:30 +0100)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Fri, 29 Sep 2006 09:30:18 +0000 (10:30 +0100)
In vmx_assist, the copy for new/old context and vmx assist magic are
all using physical address, while hvm_copy will use the virtual address.

This may cause problem when guest jump directly from real mode to
paging mode.

Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/hvm/hvm.c
xen/arch/x86/hvm/vmx/vmx.c
xen/include/asm-x86/hvm/support.h

index f84d93d5f6ea2ce26977bd9e1342152d8c41449b..e8ccdad0a66139eb795e654826c122d6a8e74d94 100644 (file)
@@ -389,44 +389,59 @@ void hvm_hlt(unsigned long rflags)
 }
 
 /*
- * Copy from/to guest virtual.
+ * __hvm_copy():
+ *  @buf  = hypervisor buffer
+ *  @addr = guest virtual or physical address to copy to/from
+ *  @size = number of bytes to copy
+ *  @dir  = HVM_COPY_IN / HVM_COPY_OUT
+ *  @phy  = interpret addr as physical or virtual address?
+ * Returns TRUE on success.
  */
-int hvm_copy(void *buf, unsigned long vaddr, int size, int dir)
+static int __hvm_copy(
+    void *buf, unsigned long addr, int size, int dir, int phy)
 {
     struct vcpu *v = current;
-    unsigned long gfn;
     unsigned long mfn;
-    char *addr;
+    char *p;
     int count;
 
-    while (size > 0) {
-        count = PAGE_SIZE - (vaddr & ~PAGE_MASK);
-        if (count > size)
-            count = size;
-
-        gfn = shadow_gva_to_gfn(v, vaddr);
-        mfn = mfn_x(sh_vcpu_gfn_to_mfn(v, gfn));
+    while ( size > 0 )
+    {
+        count = min_t(int, PAGE_SIZE - (addr & ~PAGE_MASK), size);
 
-        if (mfn == INVALID_MFN)
+        mfn = phy ? 
+            get_mfn_from_gpfn(addr >> PAGE_SHIFT) :
+            mfn_x(sh_vcpu_gfn_to_mfn(v, shadow_gva_to_gfn(v, addr)));
+        if ( mfn == INVALID_MFN )
             return 0;
 
-        addr = (char *)map_domain_page(mfn) + (vaddr & ~PAGE_MASK);
+        p = (char *)map_domain_page(mfn) + (addr & ~PAGE_MASK);
 
-        if (dir == HVM_COPY_IN)
-            memcpy(buf, addr, count);
+        if ( dir == HVM_COPY_IN )
+            memcpy(buf, p, count);
         else
-            memcpy(addr, buf, count);
+            memcpy(p, buf, count);
 
-        unmap_domain_page(addr);
+        unmap_domain_page(p);
 
-        vaddr += count;
-        buf += count;
+        addr += count;
+        buf  += count;
         size -= count;
     }
 
     return 1;
 }
 
+int hvm_copy_phy(void *buf, unsigned long paddr, int size, int dir)
+{
+    return __hvm_copy(buf, paddr, size, dir, 1);
+}
+
+int hvm_copy(void *buf, unsigned long vaddr, int size, int dir)
+{
+    return __hvm_copy(buf, vaddr, size, dir, 0);
+}
+
 /*
  * HVM specific printbuf. Mostly used for hvmloader chit-chat.
  */
index 884acb3ceac3278b6c42550445038329786a3ebd..b9b271a987b5bc29ef8fce784171c2d790822248 100644 (file)
@@ -1371,7 +1371,7 @@ static int vmx_assist(struct vcpu *v, int mode)
     u32 cp;
 
     /* make sure vmxassist exists (this is not an error) */
-    if (!hvm_copy(&magic, VMXASSIST_MAGIC_OFFSET, sizeof(magic), HVM_COPY_IN))
+    if (!hvm_copy_phy(&magic, VMXASSIST_MAGIC_OFFSET, sizeof(magic), HVM_COPY_IN))
         return 0;
     if (magic != VMXASSIST_MAGIC)
         return 0;
@@ -1385,20 +1385,20 @@ static int vmx_assist(struct vcpu *v, int mode)
          */
     case VMX_ASSIST_INVOKE:
         /* save the old context */
-        if (!hvm_copy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), HVM_COPY_IN))
+        if (!hvm_copy_phy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), HVM_COPY_IN))
             goto error;
         if (cp != 0) {
             if (!vmx_world_save(v, &c))
                 goto error;
-            if (!hvm_copy(&c, cp, sizeof(c), HVM_COPY_OUT))
+            if (!hvm_copy_phy(&c, cp, sizeof(c), HVM_COPY_OUT))
                 goto error;
         }
 
         /* restore the new context, this should activate vmxassist */
-        if (!hvm_copy(&cp, VMXASSIST_NEW_CONTEXT, sizeof(cp), HVM_COPY_IN))
+        if (!hvm_copy_phy(&cp, VMXASSIST_NEW_CONTEXT, sizeof(cp), HVM_COPY_IN))
             goto error;
         if (cp != 0) {
-            if (!hvm_copy(&c, cp, sizeof(c), HVM_COPY_IN))
+            if (!hvm_copy_phy(&c, cp, sizeof(c), HVM_COPY_IN))
                 goto error;
             if (!vmx_world_restore(v, &c))
                 goto error;
@@ -1412,10 +1412,10 @@ static int vmx_assist(struct vcpu *v, int mode)
          */
     case VMX_ASSIST_RESTORE:
         /* save the old context */
-        if (!hvm_copy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), HVM_COPY_IN))
+        if (!hvm_copy_phy(&cp, VMXASSIST_OLD_CONTEXT, sizeof(cp), HVM_COPY_IN))
             goto error;
         if (cp != 0) {
-            if (!hvm_copy(&c, cp, sizeof(c), HVM_COPY_IN))
+            if (!hvm_copy_phy(&c, cp, sizeof(c), HVM_COPY_IN))
                 goto error;
             if (!vmx_world_restore(v, &c))
                 goto error;
index 4a0161298e8abb3494acc8683d24f30da3addeac..1052a922ca37f1e21ef04a629e67d99df5d9add2 100644 (file)
@@ -138,6 +138,7 @@ extern int hvm_enabled;
 
 enum { HVM_COPY_IN = 0, HVM_COPY_OUT };
 extern int hvm_copy(void *buf, unsigned long vaddr, int size, int dir);
+extern int hvm_copy_phy(void *buf, unsigned long vaddr, int size, int dir);
 
 extern void hvm_setup_platform(struct domain* d);
 extern int hvm_mmio_intercept(ioreq_t *p);